home *** CD-ROM | disk | FTP | other *** search
- {I found a few errors and made a few improvements with my INI file
- handler I posted this earlier.}
-
- {$A+,B-,D-,F-,G-,I-,L-,N-,O-,P-,Q-,R-,S+,T-,V-,X+}
-
- {INI Version 1.2 Copr. 1996 Brad Zavitsky
- FREEWARE: Swag/Commercial use fine
-
- Thanks to Andrew Eigus for his great EnhDos unit from which I got
- Pas2Pchar
-
- Version Info
- 1.1
- ====
- o Fixed error, needed StrNew instead of StrCopy
- o Added support for TP6- users.
-
- 1.2
- ====
- o Better memory detection: now find paragraph size
- o Optimized memory testing
- o Entries will not be added if the entry or value is blank
- o Fixed bug in split
- o Added a comment delimeter set
- o Added comments to source code
- o Optimized space/tab stripping for memory
- o Made FName a constant
- o Made list global
- }
-
- unit INI; {031496}
-
- interface
-
- {$IFDEF VER70}
- uses Strings;
- {$ENDIF}
-
- type
- CSet = set of Char;
- TEntry = string[32];
- {Linked list to store INI entries and values}
- PEntryList = ^TEntryList;
- TEntryList = record
- Entry,
- Value: PChar;
- Next: PEntrylist;
- end;
-
- const
- {If these characters precede a line, it will be counted as a comment}
- CommentDelim: CSet = [';','[','#'];
-
- var
- List: PEntryList; {Holds entries and values}
-
-
- {Load the ini file into a linked list; this must be done before
- attempting
- to get any entries
- Returns:
- 0 = Everything is fine
- 1 = Error opening (ie.. File not found)
- 2 = Not enough memory (remember to call freeini to get rid of already
- stored variables}
- function LoadINI(const FName: string): Integer;
- {Frees the memory allocated from LoadINI}
- procedure FreeINI;
- {Gets the value from a specified entry}
- function GetEntry(Entry: TEntry; const Default: string): string;
-
- implementation
-
- var
- S,E,V: string; {Temporary strings, E=Entry, V=Value}
- Temp: PChar; {Used to store a string as a PChar for StrComp}
- T: Text; {INI text file}
- LNew: PEntryList; {New link}
-
- {Pascal string to ASCIIZ; Thanks to Andrew Eigus}
- function Pas2PChar(const S : string) : PChar; assembler;
- asm
- les di,S
- mov al,byte ptr [es:di]
- cmp al,0
- je @@1
- push di
- sub ah,ah
- cld
- inc al
- stosb
- add di,ax
- dec di
- sub al,al
- stosb
- pop di
- @@1:
- inc di
- mov dx,es
- mov ax,di
- end; { Pas2PChar }
-
- {ASCIIZ to Pascal}
- function PChar2Pas(P: PChar): string;
- var
- IDX: Integer;
- begin
- Idx := 0;
- while P[IDX] <> #0 do
- begin
- PChar2Pas[succ(Idx)] := P[IDX];
- inc(Idx);
- end;
- PChar2Pas[0] := Chr(Idx);
- end;
-
- {Fast uppercase function}
- function UpperCase(const S: string): string; assembler;
- asm
- push ds
- lds si, s
- les di, @result
- lodsb
- stosb
- xor ch, ch
- mov cl, al
- jcxz @empty
- @upperloop:
- lodsb
- cmp al, 'a'
- jb @cont
- cmp al, 'z'
- ja @cont
- sub al, ' '
- @cont:
- stosb
- loop @upperloop
- @empty:
- pop ds
- end;
-
- {Removes all instances of DELCHAR from the right side of S}
- function CutRight(const S: string; DelChar: Char): string;
- var
- Len: Byte;
- begin
- CutRight := S;
- Len := Ord(S[0]);
- while S[Len] = DelChar do Dec(Len);
- CutRight[0] := Chr(Len);
- end;
-
- {Removes all instances of DELCHAR from the left side of S}
- function CutLeft(const S: string; DelChar: Char): string;
- var
- Cnt: Byte;
- begin
- Cnt := 1;
- while S[Cnt] = DelChar do Inc(Cnt);
- CutLeft := Copy(S, Cnt, Length(S)-pred(Cnt));
- end;
-
- {Splits a INI string into 2 parts: the entry and value}
- procedure Split(const S: string; var E,V: string);
- var
- len: Byte;
- begin
- Len := Pos('=',S);
- if Len <> 0 then
- begin
- V := Copy(S, succ(Len), succ(Length(S)-Len));
- E := S;
- E[0] := chr(pred(Len));
- V := CutLeft(V, #32);
- V := CutLeft(V, #9);
- V := CutRight(V, #32);
- V := CutRight(V, #9);
- E := CutRight(E, #32);
- E := CutRight(E, #9);
- end else
- begin {Invalid entry}
- E := '';
- V := '';
- end;
- end;
-
- {String unit emulation}
- {$IFNDEF VER70}
- function StrNew(S: PChar): PChar;
- var
- I,
- L: Word;
- P: PChar;
- begin
- StrNew := nil;
- if (S<>nil) and (S^ <> #0) then
- begin
- L := 0;
- while S[L] <> #0 do inc(L);
- inc(L);
- GetMem(P,L);
- if P <> nil then for I := 0 to L do P[I] := S[I];
- StrNew := P;
- end;
- end;
-
- procedure StrDispose(S: PChar);
- var
- L: Word;
- begin
- L := 0;
- while S[L] <> #0 do inc(L);
- if S <> nil then FreeMem(S,succ(L));
- end;
-
- function StrComp(Str1, Str2: PChar): Integer;
- var
- L1,
- L2: Word;
- begin
- StrComp := 1;
- L1 := 0;
- while Str1[L1] <> #0 do inc(L1);
- l2 := 0;
- while Str2[L2] <> #0 do inc(L2);
- if L1 <> L2 then exit;
- for L1 := 0 to L2 do if Str1[L1] <> Str2[L1] then exit;
- StrComp := 0;
- end;
-
- {$ENDIF}
-
- {Calculates the amount of memory that would be actually allocated;
- Counts it in 16byte paragraphs}
- function MemUsed(M: Word): Word;
- var
- R: Byte;
- begin
- MemUsed := succ(M shr 4) shl 4;
- end;
-
- function LoadINI(const FName: string): Integer;
- begin
- assign(T, FName);
- reset(T);
- if IOResult <> 0 then {Exit if there is a file error}
- begin
- LoadINI := 1;
- Exit;
- end;
-
- while not Eof(T) do
- begin
- Readln(T, S);
- S := uppercase(S);
- S := CutLeft(S, #32); {Remove spaces and tabs}
- S := CutLeft(S, #9);
- {Make sure string is not a comment}
- if not (S[1] in CommentDelim) and (Length(S) > 0) then
- begin
- Split(S, E, V); {Split string into entry and value}
-
- {When low on memory, start checking to make sure we have enough}
- if MaxAvail < 300 then if MaxAvail < MemUsed(SizeOf(TEntryList)) +
- MemUsed(succ(Length(V)))+ MemUsed(Succ(Length(E))) then
- begin
- LoadINI := 2;
- {FreeINI;}
- CLose(T);
- Exit;
- end;
-
- if (V <> '') and (E <> '') then
- begin
- {Add new link to list}
- New(LNew);
- {Allocate new copies on the stack; we don't want the PChar's
- pointing to E and V}
- Lnew^.Entry := StrNew(Pas2Pchar(E));
- Lnew^.Value := StrNew(Pas2Pchar(V));
- Lnew^.Next := List;
- List := LNew;
- end;
- end;
- end;
-
- LoadINI := 0;
- close(T);
- end;
-
- procedure FreeINI;
- begin
- while List <> nil do
- begin
- StrDispose(List^.Entry);
- StrDispose(List^.Value);
- LNew := List;
- List := List^.Next;
- Dispose(Lnew);
- end;
- end;
-
- function GetEntry(Entry: TEntry; const Default: string): string;
- var
- NotFound: Boolean;
- begin
- NotFound := True;
- LNew := List;
- Entry := uppercase(Entry);
- {Make this a PCHAR so we can use StrComp on it}
- Temp := Pas2Pchar(Entry);
- while (LNew <> nil) and NotFound do
- begin
- if StrComp(Lnew^.Entry, Temp) = 0 then
- begin
- NotFound := False;
- GetEntry := PChar2Pas(LNew^.Value);
- end;
- Lnew := LNew^.Next;
- end;
- {Return Default uppercase, to provide consistancy}
- if NotFound then GetEntry := uppercase(Default);
- end;
-
- end.